package cc.linker.steplink.crm.merchanth5.service.integral;

import cc.linker.steplink.crm.commons.BeanMapUtils;
import cc.linker.steplink.crm.commons.FeeConstants;
import cc.linker.steplink.crm.commons.TradeTypeConstants;
import cc.linker.steplink.crm.commons.constant.WcPayConstant;
import cc.linker.steplink.crm.commons.enums.IntegralEnums;
import cc.linker.steplink.crm.commons.http.HttpService;
import cc.linker.steplink.crm.commons.lock.LettuceLock;
import cc.linker.steplink.crm.commons.model.SystemProperties;
import cc.linker.steplink.crm.commons.model.WcPayProperties;
import cc.linker.steplink.crm.commons.utils.NumberUtils;
import cc.linker.steplink.crm.commons.utils.TransactionOrderUtil;
import cc.linker.steplink.crm.merchanth5.dao.MallDao;
import cc.linker.steplink.crm.merchanth5.dao.acs.PurchaseProcessDao;
import cc.linker.steplink.crm.merchanth5.dao.integral.IntegralH5Dao;
import cc.linker.steplink.crm.merchanth5.model.OrderAddressDto;
import cc.linker.steplink.crm.merchanth5.pojo.ShoppingCartGoodsPo;
import cc.linker.steplink.crm.merchanth5.pojo.acs.TradeInfo;
import cc.linker.steplink.crm.merchanth5.pojo.integral.CheckIntegralOrderPo;
import cc.linker.steplink.crm.merchanth5.pojo.integral.IntegralGoodsPo;
import cc.linker.steplink.crm.merchanth5.pojo.integral.IntegralGoodsSpec;
import cc.linker.steplink.crm.merchanth5.pojo.integral.IntegralSku;
import cc.linker.steplink.crm.merchanth5.service.ColumnService;
import cc.linker.steplink.crm.merchanth5.service.CustomerIntegralService;
import cc.linker.steplink.crm.merchanth5.service.MaiBaoLaService;
import cc.linker.steplink.crm.merchanth5.service.MallBoomService;
import cc.linker.steplink.crm.merchanth5.service.acs.PurchaseProcessNewService;
import cc.linker.steplink.crm.merchanth5.service.redis.ScoreActiveCacheService;
import cc.linker.steplink.crm.merchanth5.util.ParamSignUtils;
import cc.linker.steplink.crm.response.GlobalException;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import org.springframework.util.StringUtils;

import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
public class IntegralH5Service {

    // 锁
    public static final String INTEGRAL_CREATE_ORDER_LOCK = "INTEGRAL:CREATE_ORDER_LOCK";
    // 调用返回结果
    public static final String INTEGRAL_CREATE_ORDER_RESULT = "INTEGRAL:CREATE_ORDER_RESULT";
    // 分账信息
    public static final String ACS_CREATE_ORDER_INFO = "ACS:CREATE_ORDER_INFO";

    // 单商品明细（退款和下发用）
    public static final String ACS_CREATE_GOODS_INFO = "ACS:CREATE_GOODS_INFO";

    private static final DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    @Autowired
    private IntegralH5Dao integralH5Dao;
    @Autowired
    private MallDao mallDao;
    @Autowired
    private LettuceLock lettuceLock;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private DataSourceTransactionManager txManager;

    @Autowired
    private CustomerIntegralService customerIntegralService;
    @Autowired
    private MaiBaoLaService maiBaoLaService;
    @Autowired
    private HttpService httpService;
    @Autowired
    private WcPayProperties wcPayProperties;
    @Autowired
    private SystemProperties systemProperties;
    @Autowired
    private PurchaseProcessDao purchaseProcessDao;
    @Autowired
    private PurchaseProcessNewService purchaseProcessNewService;
    @Autowired
    private ScoreActiveCacheService scoreActiveCacheService;
    @Autowired
    private ColumnService columnService;
    @Autowired
    private MallBoomService mallBoomService;
    @Value("${system.scrm.acsScrmWebUrl}")
    private String scrmH5Url;
    @Value("${casclient.clientHost}")
    private String clientHost;

    public Map getIntegralGoodsInfo(Long goodsId, String orgId,String customerId) {
        if (goodsId == null) {
            throw GlobalException.build("商品id不能为空！");
        }
        IntegralGoodsPo goodsPo = integralH5Dao.getIntegralGoodsInfo(goodsId);
        if(goodsPo==null || goodsPo.getGoodsId()==null){
            throw GlobalException.build(404,"商品已失效！");
        }
        List<IntegralGoodsSpec> goodsSpec = integralH5Dao.getSpecByGoodsId(goodsId);
        goodsPo.setGoodsSpec(goodsSpec);
        List<IntegralSku> sku = integralH5Dao.getSkuByGoodsId(goodsId);
        goodsPo.setSku(sku);
        Map goodsMap = BeanMapUtils.beanToMap(goodsPo);
        if(!StringUtils.isEmpty(goodsPo.getQuotaVips())){
            List<Map> vipList = integralH5Dao.getQuotaVipList(goodsPo.getQuotaVips(),customerId);
            goodsMap.put("quotaVipList",vipList);
        }
        return goodsMap;
    }

    public List<CheckIntegralOrderPo> checkOrder(Map<String, Object> param) {
        List<CheckIntegralOrderPo> checkIntegralOrderPo = new ArrayList<CheckIntegralOrderPo>();
        Integer goodsId = null;
        Integer buyCount = (Integer) param.get("buyCount");
        if (param.containsKey("goodsId") && param.get("goodsId") != null) {
            goodsId = Integer.valueOf(param.get("goodsId").toString());
        }
        if (goodsId != null && goodsId != 0 && buyCount != 0) {
            CheckIntegralOrderPo orderPo = new CheckIntegralOrderPo();
            List<ShoppingCartGoodsPo> goodsPoList = new ArrayList<>();
            long orderIntegralTemp = 0L;
            Integer goodsNum = 0;
            long goodsIntegral = 0L;
            long goodsAmount = 0L;
            long orderAmountTemp = 0L;
            // 直接购买联盟商家的商品
            ShoppingCartGoodsPo goodsPo = integralH5Dao.checkShoppingGoodsOrder(param);
            if (null == goodsPo) {
                throw GlobalException.build("商品失效，请重新确认订单。");
            }
            if (buyCount > goodsPo.getGoodsCount()) {
                throw GlobalException.build("商品已达上限");
            }
            Integer goodsType = goodsPo.getGoodsType();
            if(goodsType==1) {
                int quotaNum = goodsPo.getQuotaNum();
                int isQuota = this.quotaCount(Long.valueOf(goodsId.toString()), param.get("customerId").toString(), quotaNum);
                goodsPo.setQuotaNum(isQuota);
            }
                Long goodsAmountTemp = goodsPo.getAmountCent();
                Long integral = goodsPo.getIntegral();
                goodsPo.setBuyCount(buyCount);
                goodsNum = goodsNum + goodsPo.getBuyCount();
                goodsIntegral = goodsIntegral + integral * buyCount ;
                goodsAmount = goodsAmount + goodsAmountTemp * buyCount ;
                orderAmountTemp = orderAmountTemp + goodsAmountTemp * buyCount;
                orderIntegralTemp = orderIntegralTemp + integral * buyCount;

                // 需要计算
                // 总
                long total = orderIntegralTemp ;
                // 商
                goodsPoList.add(goodsPo);
                orderPo.setGoodsNum(goodsNum);
                orderPo.setPaymentPoints(total);
                orderPo.setGoodsIntegral(goodsIntegral);
                orderPo.setGoodsAmount((goodsAmount / 100.00));
                orderPo.setOrderAmount((orderAmountTemp / 100.00));
                orderPo.setOrderTotalPrice((orderAmountTemp / 100.00));
                orderPo.setOrderTotalPriceTemp(orderAmountTemp);
                if (goodsPoList.size() > 0) {
                    orderPo.setGoodsList(goodsPoList);
                }
                checkIntegralOrderPo.add(orderPo);
        }
        return checkIntegralOrderPo;
    }

    public Map createOrder(Map<String, Object> param) {
        if (!param.containsKey("orderSource")) {
            param.put("orderSource", "1");
        }
        Map map = new HashMap();
        // 获取地址
        OrderAddressDto orderAddressDto = mallDao.getDefaultReceiveAddress(param);
        // 用户id
        String customerId = (String) param.get("customerId");
        // 机构id
        String orgId = (String) param.get("orgId");
        String orderSn ="";
        // endregion
        // 只针对用户上了锁，后期可以优化
        //  region 锁，单个用户同一个时间只能下一个单，防止刷单
        String lockKey = INTEGRAL_CREATE_ORDER_LOCK + customerId;
        String requestId = UUID.randomUUID().toString();
        boolean lock = lettuceLock.tryLock(lockKey,requestId,2, TimeUnit.MINUTES);
        if (!lock) {
            throw GlobalException.build("请勿重复购买");
        }
        if(StringUtils.isEmpty(param.get("orderSn")) && (StringUtils.isEmpty(param.get("goodsId")) || StringUtils.isEmpty(param.get("goodsNum")))){
            throw GlobalException.build("参数错误");
        }
        try {
            if(!StringUtils.isEmpty(param.get("orderSn"))){
                orderSn = param.get("orderSn").toString();
                String s = stringRedisTemplate.opsForValue().get(INTEGRAL_CREATE_ORDER_RESULT + orderSn);

                if(StringUtils.isEmpty(s) && (param.get("orderSource") == null || "1".equals(param.get("orderSource").toString()))){
                    throw GlobalException.build("该订单已超时！");
                }
                // 知识付费支付未支付订单需要判断是否已经购买完成
                List<Map<String, Object>> orderInfoList = integralH5Dao.getOrderInfoByPaySn(orderSn);
                if (orderInfoList != null && orderInfoList.size() == 1) {
                    Map<String, Object> orderInfo = orderInfoList.get(0);
                    Integer orderGoodsType = (Integer) orderInfo.get("orderGoodsType");
                    if (orderGoodsType != null && orderGoodsType == 2) {
                        // 是知识付费
                        String orderGoodsId = "";
                        if(!StringUtils.isEmpty(orderInfo.get("originalGoodsId"))){
                            orderGoodsId =orderInfo.get("originalGoodsId").toString();
                        }
                        String columnGoodsId = purchaseProcessDao.getColumnGoodsIdByContentGoodsId(orderGoodsId);
                        if (columnGoodsId == null) {
                            columnGoodsId = "";
                        }
                        Map<String, Object> maps = new HashMap<>();
                        maps.put("goodsId", orderGoodsId);
                        maps.put("customerId", customerId);
                        maps.put("columnGoodsId", columnGoodsId);
                        boolean isPurchase = columnService.ifPurchase(maps);
                        if (isPurchase) {
                            throw GlobalException.build("您已购买");
                        }
                    }
                }

                if(param.get("orderSource") == null || "1".equals(param.get("orderSource").toString())){
                    //region app来源先返回订单号之后去小程序获取签名
                    map = (Map) JSON.parse(s);
                    map.put("orderSn", orderSn);
                }else {
                    map = new HashMap<>();
                    map.put("status", -1);
                    map.put("orderSn", orderSn);
                }
            }

            // 商品id
            String goodsId = "";
            if(!StringUtils.isEmpty(param.get("goodsId"))){
                goodsId = param.get("goodsId").toString();
            }

            // 生成订单，统计商品价格、订单价格
            if (!StringUtils.isEmpty(goodsId)) {
                //region 这一部分是商品购买
                LOGGER.info("下单进入goodsId方法");
                // 直接购买商品
                // 订单sn
                orderSn = TransactionOrderUtil.TYPE_INTEGRAL + this.getUniquePrimaryKey();
                param.put("orderSn", orderSn);
                param.put("paySn", orderSn);
                // 生成订单
                map = this.insertIntegralOrder(param, orderAddressDto,customerId,orgId);
            }
        }finally {
            // 解锁
            lettuceLock.releaseLock(lockKey,requestId);
        }
        return map;
    }


    /**
     * 直接购买生成订单
     */
    private Map<String, Object> insertIntegralOrder(Map<String, Object> map, OrderAddressDto orderAddressDto,String customerId,String orgId) throws GlobalException {
        Integer goodsNum = (Integer) map.get("goodsNum");
        String orderSn = (String) map.get("orderSn");
        String skuId = "" ;
        if(!StringUtils.isEmpty(map.get("skuId"))){
            skuId = map.get("skuId").toString();
        }
        if(null == goodsNum || goodsNum == 0){
            throw GlobalException.build("参数错误(error:goodsNum)");
        }
        ShoppingCartGoodsPo goodsPo = integralH5Dao.checkShoppingGoodsOrder(map);
        if (goodsPo == null || (!StringUtils.isEmpty(goodsPo.getSkuId()) && StringUtils.isEmpty(skuId))) {
            throw GlobalException.build("商品失效，请重新下单");
        }
        if (goodsPo.getIsDelete() == 1 || goodsPo.getGoodsStatus() != 1) {
            throw GlobalException.build("商品不存在或已下架");
        }
        if (goodsPo.getGoodsCount() < goodsNum) {
            throw GlobalException.build("商品库存不足");
        }
        if(!StringUtils.isEmpty(skuId) && 1!=goodsPo.getSkuIsAble()){
            throw GlobalException.build("该规格已失效！");
        }
        Integer orderGoodsType = goodsPo.getGoodsType();
        if (orderGoodsType != null && orderGoodsType == 2) {
            // 是知识付费
            Long orderGoodsId = goodsPo.getOriginalGoodsId();
            if(orderGoodsId!=null){
                String orderGoodsIds = orderGoodsId.toString();
                String columnGoodsId = purchaseProcessDao.getColumnGoodsIdByContentGoodsId(orderGoodsIds);
                if (columnGoodsId == null) {
                    columnGoodsId = "";
                }
                Map<String, Object> maps = new HashMap<>();
                maps.put("goodsId", orderGoodsId);
                maps.put("customerId", customerId);
                maps.put("columnGoodsId", columnGoodsId);
                boolean isPurchase = columnService.ifPurchase(maps);
                if (isPurchase) {
                    throw GlobalException.build("您已购买");
                }
            }
        }
        if (orderAddressDto == null) {
            orderAddressDto = new OrderAddressDto();
        }
        // 商品总价
        long goodsAmountCent = goodsPo.getAmountCent() * goodsNum;
        map.put("goodsAmountCent", goodsAmountCent);
        // 商品积分
        long goodsIntegral = goodsPo.getIntegral() * goodsNum;
        map.put("integral", goodsIntegral);
        map.put("integralGoods", goodsPo.getIntegral());
        map.put("orderGoodsType", goodsPo.getGoodsType());
        //判断用户积分
        Map<String, Object> integralCustomerInfo = this.customerIntegralService.getIntegralCustomerInfo(customerId,orgId);
        int quotaNum = goodsPo.getQuotaNum();
        int quotaLevel = goodsPo.getQuotaLevel();
        //还剩多少可以购买
        int quotaCount = this.quotaCount(goodsPo.getGoodsId(),customerId,quotaNum);
        Long customerScore = 0L;
        if(quotaCount!=-1 && quotaCount<goodsNum && quotaNum!=-1){
            throw GlobalException.build("每人限购"+quotaNum+"件");
        }
        if(!StringUtils.isEmpty(goodsPo.getQuotaVips())){
            Integer count = integralH5Dao.getVipListByCustomerId(customerId,goodsPo.getQuotaVips());
            if(count==0){
                throw GlobalException.build("拥有指定权益卡才能兑换！");
            }
        }
        Map maps = new HashMap();
        Long currentGrowthScore = 0L;
        if(integralCustomerInfo!=null && !StringUtils.isEmpty(integralCustomerInfo.get("customerGrowthScore"))){
            currentGrowthScore = Long.valueOf(integralCustomerInfo.get("customerGrowthScore").toString());
        }
        Integer levelOrder =0;
        maps.put("orgId",orgId);
        List<Map<String, Object>> levels = integralH5Dao.listLevels(maps);
        maps.put("levels", levels);
        if(levels.size()>0) {
            //获取最后一个等级
            Map<String, Object> endLevel = levels.get(levels.size()-1);
            //如果用户当前等级大于最后一个等级的经验值则当前等级就是最后一个等级
            if(currentGrowthScore>= (Long) endLevel.get("levelScore")) {
                levelOrder = (Integer) endLevel.get("levelOrder");
            }else{
                //如果不是最后一个等级，遍历所有找到对应的当前等级
                for (int i = 0; i <= levels.size()-1; i++) {
                    Map<String, Object> level = levels.get(i);
                    //获取当前等级数据
                    if ((Long) level.get("levelScore") > currentGrowthScore) {
                        if (i != 0) {
                            levelOrder = (Integer) levels.get(i - 1).get("levelOrder");
                        }
                        break;
                    }
                }
            }
        }
        if(levelOrder<quotaLevel){
            throw GlobalException.build("会员等级大于VIP"+quotaLevel+"以上");
        }
        if(integralCustomerInfo!=null && !StringUtils.isEmpty(integralCustomerInfo.get("customerScore"))){
            customerScore = Long.valueOf(integralCustomerInfo.get("customerScore").toString());
        }
        if(goodsIntegral>customerScore){
            throw GlobalException.build("用户积分不够！");
        }else {
            String msg = "兑换商品";
            Long score = -goodsIntegral;
            this.customerIntegralService.addIntegralCustomerLog(customerId,msg, IntegralEnums.customerScore.toString(),score.toString(),IntegralEnums.other.toString(),orgId);
        }
        // 订单总价
        long orderAmountCent = goodsAmountCent;
        map.put("orderTotalPriceCent", orderAmountCent);
        map.put("goods", goodsPo);
        map.put("address", orderAddressDto);

        map.put("integralPaymentAmount", 0);
        map.put("orderAmountCent", orderAmountCent);
        map.put("knowledgeType", goodsPo.getKnowledgeType());

        //事务管理
        DefaultTransactionDefinition def = new DefaultTransactionDefinition();
        def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
        TransactionStatus status = txManager.getTransaction(def);
        int updateCount=this.updateCount(goodsPo.getGoodsId(),skuId,goodsNum);
        if (updateCount == 0) {
            throw GlobalException.build("商品库存不足");
        }
        map.put("paymentState",0);
        if(orderAmountCent>0){
            map.put("orderState",10);
            map.put("status",0);
        }else{
            map.put("orderState",20);
            map.put("status",1);
            if(goodsPo.getGoodsType()!=null && goodsPo.getGoodsType()==2){
                map.put("orderState",40);
                map.put("status",2);
                map.put("paymentState",1);
            }
        }
        integralH5Dao.insertOrderByMap(map);
        //增加日志
        Map<String, Object> log = new HashMap<String, Object>();
        log.put("logId", UUID.randomUUID().toString());
        log.put("customerId", customerId);
        log.put("scoreValue", "-"+goodsIntegral);
        log.put("scoreType", 6);
        log.put("actionRemark", "兑换"+goodsPo.getGoodsName()+"商品扣除"+goodsIntegral+"积分");
        integralH5Dao.addIntegralLog(log);
        integralH5Dao.insertOrderGoodsByMap(map);
        txManager.commit(status);
        map.put("goodsId", goodsPo.getGoodsId());
        Long recId = -1L;
        if(!StringUtils.isEmpty(map.get("recId"))){
            recId = Long.valueOf(map.get("recId").toString());
        }
        if(orderAmountCent>0){
            if (map.get("orderSource") == null || "1".equals(map.get("orderSource").toString())) {
                //获取签名
                return this.getSign(map, (int) orderAmountCent, goodsPo.getGoodsName(), orderSn, recId, (Integer) map.get("payMode"), orgId, customerId);
            }else {
                //region app来源先返回订单号之后去小程序获取签名
                Map<String, Object> res = new HashMap<>();
                res.put("status", -1);
                res.put("orderSn", orderSn);
                return res;
            }
        }else {
            //发送模板消息(调试要注释)
            Map<String, String> orderParam = new HashMap<>();
            orderParam.put("sendType", "payment");
            orderParam.put("orgId", orgId);
            orderParam.put("goodsName", goodsPo.getGoodsName());
            orderParam.put("orderSn", orderSn);
            orderParam.put("orderAmount", NumberUtils.fenToYuan(Long.valueOf("0")));
            String orderTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
            orderParam.put("orderTime", orderTime);
            String h5url = scrmH5Url + "/userCenter.html?goto=orderlist?activeTab=20";
            String h5urlEncode = null;
            try {
                h5urlEncode = URLEncoder.encode(h5url, "UTF-8");
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
            String url = clientHost + "/personal/login?token=" + purchaseProcessDao.getTokenByOrgId(orgId) + "&m=" + h5urlEncode;
            orderParam.put("url", url);
            orderParam.put("openid", purchaseProcessDao.getOpenIdByCustomerId(customerId));
            //orgId-机构id,goodsName-商品名称,orderSn-订单号,orderAmount-订单金额(非支付金额),orderTime-支付时间,url-订单列表页面,openid-购买人的openid
            this.setTemplateMessageList(orderParam);


            //全积分
            Map<String, Object> res = new HashMap<>();
            res.put("orderId",map.get("orderId"));
            res.put("orderSn",orderSn);
            res.put("orderSn",orderSn);
            res.put("status","-2");
            res.put("txsn","");
            res.put("IsZeroBuy","1");
            return res;
        }
    }


    private int updateCount(Long goodsId, String skuId, Integer goodsNum) {
        int updateCount = integralH5Dao.updateGoodsCount(goodsId,goodsNum);
        if(updateCount>0){
            if(!StringUtils.isEmpty(skuId)){
                integralH5Dao.updateSkuGoodsCount(skuId,goodsNum);
            }
        }
        return updateCount;
    }


    public String getUniquePrimaryKey() {
        String primaryKey = TransactionOrderUtil.getPrimaryKey();
        String cacheKey = "unique_order_id";
        Long increment = stringRedisTemplate.opsForValue().increment(cacheKey, 1);
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date());
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        stringRedisTemplate.expireAt(cacheKey, calendar.getTime());
        if (null == increment) {
            increment = 0L;
        }
        return primaryKey + increment;
    }

    public Map<String, Object> quota(Long goodsId, Long skuId, String customerId,String orgId) {
        Map map = new HashMap();
        //判断用户积分
        Map<String, Object> integralCustomerInfo = this.customerIntegralService.getIntegralCustomerInfo(customerId,orgId);
        Long customerScore = 0L;
        if(integralCustomerInfo!=null && !StringUtils.isEmpty(integralCustomerInfo.get("customerScore"))){
            customerScore = Long.valueOf(integralCustomerInfo.get("customerScore").toString());
        }
        map.put("goodsId",goodsId);
        map.put("skuId",skuId);
        ShoppingCartGoodsPo goodsPo = integralH5Dao.checkShoppingGoodsOrder(map);
        long goodsIntegral = 0L;
        long count = 0L;
        long goodsCount = 0L;
        int goodsStatus = 3;
        int isDelete = 0;
        int skuIsAble = 0;
        if(goodsPo!=null){
            goodsIntegral = goodsPo.getIntegral();
            count = customerScore/goodsIntegral;
            goodsCount = goodsPo.getGoodsCount();
            goodsStatus = goodsPo.getGoodsStatus();
            isDelete = goodsPo.getIsDelete();
            if(!StringUtils.isEmpty(skuId)){
                skuIsAble = goodsPo.getSkuIsAble();
            }
            int quotaNum = 0;
            int quotaLevel = 0;
            quotaNum = goodsPo.getQuotaNum();
            quotaLevel = goodsPo.getQuotaLevel();
            int isQuota = this.quotaCount(goodsId,customerId,quotaNum);
            map.put("quota",isQuota);
            Map maps = new HashMap();
            Long currentGrowthScore = 0L;
            if(integralCustomerInfo!=null && !StringUtils.isEmpty(integralCustomerInfo.get("customerGrowthScore"))){
                currentGrowthScore = Long.valueOf(integralCustomerInfo.get("customerGrowthScore").toString());
            }
            Integer levelOrder =0;
            maps.put("orgId",orgId);
            List<Map<String, Object>> levels = integralH5Dao.listLevels(maps);
            maps.put("levels", levels);
            if(levels.size()>0) {
                //获取最后一个等级
                Map<String, Object> endLevel = levels.get(levels.size()-1);
                //如果用户当前等级大于最后一个等级的经验值则当前等级就是最后一个等级
                if(currentGrowthScore>= (Long) endLevel.get("levelScore")) {
                    levelOrder = (Integer) endLevel.get("levelOrder");
                }else{
                    //如果不是最后一个等级，遍历所有找到对应的当前等级
                    for (int i = 0; i <= levels.size()-1; i++) {
                        Map<String, Object> level = levels.get(i);
                        //获取当前等级数据
                        if ((Long) level.get("levelScore") > currentGrowthScore) {
                            if (i != 0) {
                                levelOrder = (Integer) levels.get(i - 1).get("levelOrder");
                            }
                            break;
                        }
                    }
                }
            }
            map.put("levelOrder",levelOrder);
            map.put("quotaLevel",quotaLevel);
        }
        map.put("customerScore",customerScore);
        map.put("count",count);
        map.put("goodsCount",goodsCount);
        map.put("goodsStatus",goodsStatus);
        map.put("isDelete",isDelete);
        if(!StringUtils.isEmpty(skuId)){
            map.put("skuIsAble",skuIsAble);
        }
        map.put("quotaVip",0);
        if(!StringUtils.isEmpty(goodsPo.getQuotaVips())){
            Integer countQuotaVip = integralH5Dao.getVipListByCustomerId(customerId,goodsPo.getQuotaVips());
            if(countQuotaVip==0){
                map.put("quotaVip",1);
            }
        }
        return map;
    }

    /**
     * 是否限购
     * @param goodsId
     * @param customerId
     * @param quotaNum
     * @return
     */
    public int quotaCount( Long goodsId,String customerId,int quotaNum){
        int quotaCount = -1;
        int buyCount = integralH5Dao.getBuyCountByGoodsId(goodsId,customerId);
        if(quotaNum<=buyCount && quotaNum!=-1){
            quotaCount = 0;
        }
        if(quotaNum>buyCount){
            quotaCount = quotaNum - buyCount;
        }

        return quotaCount;
    }


    public void checkReceiveOrder(Map<String, Object> params) {
        Integer i = integralH5Dao.checkOrderIfReceive(params);
        if (i != 0) {
            throw GlobalException.build("订单已确认");
        }
        //订单状态更新
        integralH5Dao.checkReceiveOrder(params);
        // 通过订单id找订单sn
        String orderSn = "";
        if(!StringUtils.isEmpty(params.get("orderId"))){
            orderSn = integralH5Dao.getOrderSnByOrderId(Long.valueOf(params.get("orderId").toString()));
        }
        if(!StringUtils.isEmpty(orderSn)){
            // 无退款，更新end_time
            String orgId = (String) params.get("orgId");
            Integer freezeTime = integralH5Dao.getUnfreezeTimeByOrgId(orgId);
            if (freezeTime == null || freezeTime < 0) {
                freezeTime = 30;
            }
            // 解冻时间
            String unfreezeTime = df.format(LocalDateTime.now().plusDays(freezeTime));
            integralH5Dao.updateProtectStatusWhereAutoConfirm(orderSn, unfreezeTime);
        }

    }

    public void editOrderAddress(Map<String, Object> param) {
        OrderAddressDto orderAddressDto = mallDao.getDefaultReceiveAddress(param);
        if (orderAddressDto == null) {
            throw GlobalException.build("地址不存在或用户与地址不匹配");
        }
        param.put("addressRealName", orderAddressDto.getRealName());
        param.put("addressPhone", orderAddressDto.getPhone());
        param.put("addressProvince", orderAddressDto.getProvinceName());
        param.put("addressCity", orderAddressDto.getCityName());
        param.put("addressArea", orderAddressDto.getAreaName());
        param.put("addressDetailedAddress", orderAddressDto.getAddressInfo());
        integralH5Dao.editOrderAddress(param);
    }

    //小程序付款
    public Map payOrderByxcx(String orderSn,String openid) {
        Map param = new HashMap();
        param.put("orderSn",orderSn);
        param.put("openid",openid);
        param.put("orderSource","2");
        Map goodsMap = integralH5Dao.getSignGoodsInfo(param);
        if(goodsMap==null){
            throw GlobalException.build("无此订单！");
        }
        int totalPay = -1;
        if(!StringUtils.isEmpty(goodsMap.get("totalPay"))){
            totalPay = Integer.valueOf(goodsMap.get("totalPay").toString());
        }
        String goodsName="";
        if(!StringUtils.isEmpty(goodsMap.get("goodsName"))){
            goodsName = goodsMap.get("goodsName").toString();
        }
        Long recId = -1L;
        if(!StringUtils.isEmpty(goodsMap.get("recId"))){
            recId = Long.valueOf(goodsMap.get("recId").toString());
        }
        int payMode = -1;
        if(!StringUtils.isEmpty(goodsMap.get("payMode"))){
            payMode = Integer.valueOf(goodsMap.get("payMode").toString());
        }
        String orgId="";
        if(!StringUtils.isEmpty(goodsMap.get("orgId"))){
            orgId = goodsMap.get("orgId").toString();
        }
        String customerId="";
        if(!StringUtils.isEmpty(goodsMap.get("customerId"))){
            customerId = goodsMap.get("customerId").toString();
        }
        return this.getSign(param,totalPay,goodsName,orderSn,recId,payMode,orgId,customerId);
    }


    public Map getSign(Map param,int totalPay,String goodsName,String paySn,Long recId,Integer payMode,String orgId,String customerId)  {
        String res;
        // 签名数据，先去redis看看有没有
        String s = stringRedisTemplate.opsForValue().get(INTEGRAL_CREATE_ORDER_RESULT + paySn);
        String openid = (String) param.get("openid");
        // 如果是app来源 支付标识小程序
        String payType = "WX";
        if ("2".equals(param.get("orderSource").toString())) {
            param.put("acctType", "XCX");
            payType = "XCX";
        }
        if (!StringUtils.isEmpty(s)) {
            LOGGER.info("已经有签名=====");
            // 已生成签名
            res = s;
        } else {
            LOGGER.info("请求网关调用签名=====");
            //订单明细
            List<Map<String, Object>> tradeInfos = new ArrayList<Map<String, Object>>();
            //单商品明细（退款和下发用）
            List<Map<String, Object>> goodsTradeInfos = new ArrayList<Map<String, Object>>();
            // 仅服务费
            Map<String, Object> tradeInfo = new HashMap<>();
            tradeInfo.put("from", customerId);
            tradeInfo.put("orderSn", paySn);
            tradeInfo.put("recId", recId);
            tradeInfo.put("to", orgId);
            tradeInfo.put("amount", totalPay);
            tradeInfo.put("orderName", goodsName);
            tradeInfo.put("score",0);
            tradeInfo.put("tradeType", TradeTypeConstants.DEAL_PLATFORM_FEE);
            tradeInfo.put("payRole", 5);
            tradeInfo.put("payType", 1);
            tradeInfo.put("receiveRole", 1);
            tradeInfo.put("accountType", "");
            tradeInfo.put("receiveAccount", "");
            tradeInfos.add(tradeInfo);
            goodsTradeInfos.add(tradeInfo);

            Map<String, String> cutPercent = mallBoomService.getOrgCutByOrgId(orgId);
            Integer linkerCut = this.getCutMoney(totalPay, cutPercent.get("linkerTake"));//联汇抽成
            Integer unionbarleyCut = this.getCutMoney(totalPay, cutPercent.get("unionbarleyTake"));//大麦抽成
            Integer platformCut = linkerCut + unionbarleyCut;//手续费
            //记录支付抽成(大b)
//                this.savePlatformMoney(5, FeeConstants.MERCHANT_FEE, linkerCut, orgId, orderInfo, serialNo, unFreezeTime);
            try {
                if (linkerCut > 0) {
                    Map<String, Object> tradeParam1 = new HashMap<>();
                    tradeParam1.put("from", customerId);
                    tradeParam1.put("orderSn", paySn);
                    tradeParam1.put("recId", recId);
                    String toLink = purchaseProcessDao.getLinkIdByOrgId(orgId);
                    if(toLink==null){
                        toLink = "";
                    }
                    tradeParam1.put("to", toLink);
                    tradeParam1.put("amount", linkerCut);
                    tradeParam1.put("orderName", goodsName);
                    tradeInfo.put("score",0);
                    tradeParam1.put("tradeType", 9);
                    tradeParam1.put("receiveRole", 1);
                    tradeParam1.put("payType", 1);//金额类型 1.现金 2.金币
                    tradeParam1.put("accountType", "");

                    tradeInfos.add(tradeParam1);
                    goodsTradeInfos.add(tradeParam1);
                }
                //记录大麦抽成
                if (unionbarleyCut > 0) {
                    //支付抽成
                    Map<String, Object> tradeParam1 = new HashMap<>();
                    tradeParam1.put("from",  customerId);
                    tradeParam1.put("to", orgId);
                    tradeParam1.put("amount", unionbarleyCut);
                    tradeParam1.put("tradeType", TradeTypeConstants.PAY_CENTAGE_FEE);
                    tradeParam1.put("receiveRole", 1);
                    tradeParam1.put("payType", 1);//金额类型 1.现金 2.金币
                    tradeParam1.put("accountType", "");
                    tradeParam1.put("orderSn", paySn);
                    tradeParam1.put("recId", recId);
                    tradeParam1.put("orderName", goodsName);
                    tradeInfo.put("score",0);
                    tradeInfos.add(tradeParam1);
                    goodsTradeInfos.add(tradeParam1);
                }
                // 交易手续费
//                this.saveOrgServerMoney(TradeTypeConstants.TRADE_SERVER_FEE, platformCut, orgId, orderInfo, serialNo, unFreezeTime);
                if (platformCut > 0) {
                    //交易手续费
                    Map<String, Object> tradeParam1 = new HashMap<>();
                    tradeParam1.put("from", orgId);
                    tradeParam1.put("to", "");
                    tradeParam1.put("amount", platformCut);
                    tradeParam1.put("tradeType", TradeTypeConstants.TRADE_SERVER_FEE);
                    tradeParam1.put("receiveRole", -1);
                    tradeParam1.put("payRole", 1);
                    tradeParam1.put("payType", 1);//金额类型 1.现金 2.金币
                    tradeParam1.put("accountType", "");
                    tradeParam1.put("orderSn", paySn);
                    tradeParam1.put("recId", recId);
                    tradeParam1.put("orderName", goodsName);
                    tradeInfo.put("score",0);
                    tradeInfos.add(tradeParam1);
                    goodsTradeInfos.add(tradeParam1);
                }
            }catch (Exception e){
                e.printStackTrace();
            }

            if (payMode == 1) {
                // wx
                res = this.getResultWx(openid, paySn, totalPay, orgId, payType);
            } else if (payMode == 2 || payMode == 3) {
                // tl
                param.put("openId", openid);
                param.put("customerId", customerId);
                param.put("orgId", orgId);
                maiBaoLaService.checkCustomerAccount(param, payMode);
                String frontUrl = "";
                if(!StringUtils.isEmpty(param.get("frontUrl"))){
                    frontUrl = param.get("frontUrl").toString();
                }
                res = this.tlResult(orgId, totalPay, goodsName, paySn, customerId, openid, payType, payMode,frontUrl);
            } else {
                throw GlobalException.build("机构支付模式配置不正确");
            }
            // 单商品明细（退款和下发用）
            stringRedisTemplate.opsForValue().set(ACS_CREATE_GOODS_INFO + paySn, JSON.toJSONString(goodsTradeInfos), 30, TimeUnit.DAYS);
            // 分账数据
            stringRedisTemplate.opsForValue().set(ACS_CREATE_ORDER_INFO + paySn, JSON.toJSONString(tradeInfos), 30, TimeUnit.DAYS);
            // 签名数据
            stringRedisTemplate.opsForValue().set(INTEGRAL_CREATE_ORDER_RESULT + paySn, res, 60, TimeUnit.MINUTES);
        }
        Map result = (Map) JSON.parse(res);
        result.put("orderSn", paySn);
        return result;
    }

    /**
     * 计算反润金额
     *
     * @param sysAmount
     * @param cutPercent
     * @return
     */
    public Integer getCutMoney(Integer sysAmount, String cutPercent) {
        double v = sysAmount.doubleValue() * Double.valueOf(cutPercent) / 100;
        return new BigDecimal(v).setScale(0, BigDecimal.ROUND_HALF_EVEN).intValue();
    }

    /**
     * 获取微信签名
     * @param openid
     * @param paySn
     * @param totalPay
     * @param orgId
     * @return
     */
    public String getResultWx(String openid,String paySn,int totalPay,String orgId,String payType){
        String result = "";
        // 请求地址
        String url = wcPayProperties.getPayurl() + "/pay/wcpay";
        //支付网关请求封装参数
        Map<String, Object> req = this.getWxPayParam(openid, paySn, String.valueOf(totalPay), orgId,payType);
        // 请求支付网关
        try {
            // 积分抵扣后为0元
            if (totalPay != 0) {
                // 请求网关
                result = httpService.doPost(url, req);
                // 处理结果
                result = this.callResultProcessWx(result);
                stringRedisTemplate.opsForValue().set("orderType_"+paySn,"6",1, TimeUnit.HOURS);
            }
        } catch (Exception e) {
            LOGGER.error("支付网关调用异常" + e);
            throw GlobalException.build("支付网关调用异常");
        }
        return result;
    }


    /**
     * 生成微信支付调用参数
     */
    public Map<String, Object> getWxPayParam(String openId, String orderSn, String totalFee, String orgId,String payType) {
        String notifyUrl = systemProperties.getScrmUrl() + "acs/paycallbackforwx";
        String wcpayType = "STEPLINK_" + orgId;
        if("WX".equals(payType)){
            wcpayType = "STEPLINK_" + orgId;
        }else if("XCX".equals(payType)){
            wcpayType =  "STEPLINK_XCX_" + orgId;
        }
        Map<String, String> params = new HashMap<>();
        params.put("body", "step积分商城订单");
        params.put("notifyUrl", notifyUrl);
        params.put("openid", openId);
        params.put("outTradeNo", orderSn);
        params.put("timestamp", String.valueOf(System.currentTimeMillis()));
        params.put("totalFee", totalFee);
        params.put("tradeType", "JSAPI");
        params.put("wcpayType", wcpayType);
        if (systemProperties.isWxSplit()) {
            params.put("needShare", "1");
        }
        Map<String, String> appSign = ParamSignUtils.sign(params);
        params.put("appSign", appSign.get("appSign"));
        LOGGER.info("paymsg=================" + params);
        return new HashMap<>(params);
    }


    /**
     * 调用结果处理(微信)
     */
    public String callResultProcessWx(String result) throws GlobalException {
        if (StringUtils.isEmpty(result)) {
            throw GlobalException.build("操作失败");
        }
        LOGGER.info(result);
        Object parse = JSON.parse(result);
        Map ret = (Map) parse;
        if ((Integer) ret.get("rt") != 1) {
            throw GlobalException.build("支付网关调用失败");
        }
        //noinspection unchecked
        Map<String, Object> retInfo = (Map) ret.get("object");
        retInfo.put("package", "prepay_id=" + retInfo.get("prepayId"));
        return JSON.toJSONString(retInfo);
    }
    /**
     * 获取通联签名
     * @param openid
     * @param paySn
     * @param totalPay
     * @param orgId
     * @return
     */
    private String tlResult(String orgId, Integer totalPay,String goodsName, String paySn, String customerId, String openid, String payType, Integer payMode,String frontUrl) {
        // 根据配置读取 服务费、推荐费、联汇抽成、大b抽成分别给谁
        List<Map<String, Object>> cashSplitItems = new ArrayList<>();
        String orgUid = stringRedisTemplate.opsForValue().get("orgUid:"+orgId);
        String feeId = this.getCustomerIdByFeeTypeAndOrdId(FeeConstants.SERVICE_FEE, orgId,payMode);
        if(StringUtils.isEmpty(orgUid)){
            orgUid = purchaseProcessDao.getAccountUidByOrgId(orgId);
            stringRedisTemplate.opsForValue().set("orgUid:"+orgId,orgUid);
        }
        int cashAmount = totalPay;
        // 请求参数
        Map<String, Object> reqMap = new HashMap<>();

        Map<String, String> cutPercent = mallBoomService.getOrgCutByOrgId(orgId);
        String linkdrawfeeaccount = this.getCustomerIdByFeeTypeAndOrdId(FeeConstants.LINK_DRAW_FEE, orgId,payMode);
        double v = totalPay.doubleValue() * Double.valueOf(cutPercent.get("linkerTake")) / 100;
        Integer linkerCut = new BigDecimal(v).setScale(0, BigDecimal.ROUND_HALF_EVEN).intValue();
        if(linkerCut>0){
            Map<String, Object> cashSplitItem1 = new HashMap<>();
            cashSplitItem1.put("customerId", linkdrawfeeaccount);
            cashSplitItem1.put("splitAmount", linkerCut);
            cashSplitItem1.put("note", goodsName + "联汇支付抽成");
            cashSplitItem1.put("orderId", paySn);
            cashSplitItems.add(cashSplitItem1);
        }


        String orgdrawfeeaccount = this.getCustomerIdByFeeTypeAndOrdId(FeeConstants.ORG_DRAW_FEE, orgId,payMode);
        double u = totalPay.doubleValue() * Double.valueOf(cutPercent.get("unionbarleyTake")) / 100;
        Integer unionbarleyCut = new BigDecimal(u).setScale(0, BigDecimal.ROUND_HALF_EVEN).intValue();
        if(unionbarleyCut>0){
            Map<String, Object> cashSplitItem2 = new HashMap<>();
            cashSplitItem2.put("customerId", orgdrawfeeaccount);
            cashSplitItem2.put("splitAmount", unionbarleyCut);
            cashSplitItem2.put("note", goodsName + "联盟大麦支付抽成");
            cashSplitItem2.put("orderId", paySn);
            cashSplitItems.add(cashSplitItem2);
        }

        Map<String, Object> cashSplitItem3 = new HashMap<>();
        cashSplitItem3.put("customerId",orgUid);
        cashSplitItem3.put("type",1);
        cashSplitItem3.put("splitAmount", totalPay - linkerCut - unionbarleyCut);
        cashSplitItem3.put("note", "商品收益");
        cashSplitItem3.put("orderId", paySn);
        cashSplitItems.add(cashSplitItem3);

        reqMap.put("cashAmount", cashAmount);
        // 现金分账明细，JSON字符串
        if (cashSplitItems.size() > 0) {
            reqMap.put("cashSplitItems", JSON.toJSONString(cashSplitItems));
        }
        // 收款人id 收款人银行账号 金额 备注 订单sn
        // 支付后跳转前端地址
        reqMap.put("frontUrl", frontUrl);
        // 支付用户ID
        reqMap.put("customerId", customerId);
        // 商品描述
        if(goodsName.length()>40){
            goodsName = goodsName.substring(0,40);
        }
        reqMap.put("goodsName", goodsName);
        // 支付用户OPENID
        reqMap.put("openID", openid);
        // 平台订单ID
        reqMap.put("orderSn", paySn);
        // 收款用户帐号(收款用户为机构会员时必填，机构结算标识)(大b账号)
//      reqMap.put("payeeAccountNumber", orgAccountNumber);
        // 收款用户ID
        reqMap.put("payeeUserID", orgUid);
        // 余额支出账户
        reqMap.put("feeCustomerId", feeId);
        // 应用appId
        String appId = "";
        if("WX".equals(payType)){
            if (payMode == 2) {
                appId = stringRedisTemplate.opsForValue().get("appIdWX:_orgId_"+orgId);
                if(StringUtils.isEmpty(appId)) {
                    appId = purchaseProcessDao.getAppIdByOrgId(orgId);
                    stringRedisTemplate.opsForValue().set("appIdWX:_orgId_"+orgId,appId);
                }
            } else if (payMode == 3) {
                appId = stringRedisTemplate.opsForValue().get("appIdWX:_orgId_linker");
                if(StringUtils.isEmpty(appId)) {
                    appId = purchaseProcessDao.getAppIdByOrgId("linker");
                    stringRedisTemplate.opsForValue().set("appIdWX:_orgId_linker",appId);
                }
            }
        }else if("XCX".equals(payType)){
            appId = stringRedisTemplate.opsForValue().get("appIdXCX:orgId_"+orgId);
            if(StringUtils.isEmpty(appId)) {
                appId = purchaseProcessDao.getXcxAppIdByOrgId(orgId);
                if(!StringUtils.isEmpty(appId)){
                    stringRedisTemplate.opsForValue().set("appIdXCX:orgId_"+orgId,appId);
                }
            }
        }
        if (StringUtils.isEmpty(appId)) {
            throw GlobalException.build("appId获取失败");
        }
        reqMap.put("appId", appId);
        // 行业代码
        String industryCode = purchaseProcessDao.getOrgMerchantInfoByOrgId(orgId);
        reqMap.put("industryCode", industryCode);
        // 行业名称
        String industryName = purchaseProcessDao.getIndustryNameByCode(industryCode);
        reqMap.put("industryName", industryName);
        // 支付方式：WX-公众号支付；XCX-微信小程序支付
        reqMap.put("payType", payType);
        // 访问终端类型:1手机；2PC
        reqMap.put("source", 1);
        // 交易验证方式：0-无验证；1-短信验证码；2-支付密码
        reqMap.put("validateType", 0);
        // 测试环境用yt
        String alias = "";
        if(payMode == 3){
            alias = stringRedisTemplate.opsForValue().get("alias:orgId_linker");
            if(StringUtils.isEmpty(alias)) {
                alias = maiBaoLaService.getAliasByLinker();
                stringRedisTemplate.opsForValue().set("alias:orgId_linker",alias);
            }
        }
        if(payMode == 2){
            alias = stringRedisTemplate.opsForValue().get("alias:orgId_"+orgId);
            if(StringUtils.isEmpty(alias)) {
                alias = maiBaoLaService.getAlias(orgId);
                stringRedisTemplate.opsForValue().set("alias:orgId_"+orgId,alias);
            }
        }
        reqMap.put("clintType", alias);
        // 手续费
        reqMap.put("fee", 0);
        String url = wcPayProperties.getAcsurl() + WcPayConstant.TRADE_PAY_ORDER;
        // 请求支付网关
        String result = "";
        try {
            LOGGER.info("通联支付请求参数==={}", JSON.toJSONString(reqMap));
            result = httpService.doPost(url, JSON.toJSONString(reqMap), WcPayConstant.JSON);
            result = this.callResultProcess(result);
            stringRedisTemplate.opsForValue().set("orderType_"+paySn,"6",1, TimeUnit.HOURS);
        } catch (Exception e) {
            LOGGER.error("支付网关调用异常", e);
            throw GlobalException.build("支付网关调用异常");
        }
        return  result;
    }

    /**
     * 根据机构和费用类型查询分账配置账号id
     *
     * @param type  见FeeConstants
     * @param orgId 机构id
     */
    public String getCustomerIdByFeeTypeAndOrdId(String type, String orgId,Integer payMode) throws GlobalException {

        String account = stringRedisTemplate.opsForValue().get("accountType:type_"+type+"orgId_"+orgId);
        if(StringUtils.isEmpty(account)){
            account = purchaseProcessDao.getAccountByFeeTypeAndOrdId(type, orgId);
            if (StringUtils.isEmpty(account)) {
                purchaseProcessDao.insertAcsOrgDefaultConfig(orgId);
                account = purchaseProcessDao.getAccountByFeeTypeAndOrdId(type, orgId);
            }
            stringRedisTemplate.opsForValue().set("accountType:type_"+type+"_orgId_"+orgId,account);
        }
        switch (account) {
            case "A":
                String linkId = "";
                if (payMode == 2) {
                    linkId = stringRedisTemplate.opsForValue().get("linkIdType:orgId_"+orgId);
                    if(StringUtils.isEmpty(linkId)) {
                        linkId = purchaseProcessDao.getLinkIdByOrgId(orgId);
                        stringRedisTemplate.opsForValue().set("linkIdType:orgId_"+orgId,linkId);
                    }
                } else if (payMode == 3) {
                    linkId = stringRedisTemplate.opsForValue().get("linkIdType:orgId_linker");
                    if(StringUtils.isEmpty(linkId)) {
                        linkId = purchaseProcessDao.getLinkIdByLinkOrg("linker");
                        stringRedisTemplate.opsForValue().set("linkIdType:orgId_linker",linkId);
                    }
                }
                if (StringUtils.isEmpty(linkId)) {
                    throw GlobalException.build("联汇暂未开户");
                }
                return linkId;
            case "B":
                String orgUid = stringRedisTemplate.opsForValue().get("orgUid:"+orgId);
                if(StringUtils.isEmpty(orgUid)){
                    orgUid = purchaseProcessDao.getAccountUidByOrgId(orgId);
                    stringRedisTemplate.opsForValue().set("orgUid:"+orgId,orgUid);
                }
                if (StringUtils.isEmpty(orgUid)) {
                    throw GlobalException.build("机构暂未开户");
                }
                return orgUid;
            case "C":
                // 平台营销资金账户
                return "#yunBizUserId_B2C#";
            default:
                throw GlobalException.build("机构账户配置错误！");
        }
    }

    /**
     * 调用结果处理(中金)
     */
    public String callResultProcess(String result) throws GlobalException {
        if (StringUtils.isEmpty(result)) {
            throw GlobalException.build("网关调用失败");
        }
        LOGGER.info(result);
        Map resMap = (Map) JSON.parse(result);
        if (!resMap.containsKey("code")) {
            throw GlobalException.build("网关调用失败:" + resMap.get("msg"));
        }
        if (!"200".equals(resMap.get("code"))) {
            throw GlobalException.build("网关调用失败:" + resMap.get("msg"));
        }
        if (!resMap.containsKey("data")) {
            throw GlobalException.build("网关调用失败:" + resMap.get("msg"));
        }
        Map data = (Map) resMap.get("data");
        if (!data.containsKey("authCode")) {
            throw GlobalException.build("网关调用失败:" + resMap.get("msg"));
        }
        return (String) data.get("authCode");
    }

    /**
     * 积分商品支付回调
     * @param param
     */
    public void shopCallback(Map<String, Object> param) {
        LOGGER.info("订单回调参数----->"+JSON.toJSONString(param));
        String orderSn = (String) param.get("orderSn");
        if (StringUtils.isEmpty(orderSn)) {
            throw GlobalException.build("缺少参数");
        }
        Integer count = integralH5Dao.countTradeByPaySn(orderSn);
        if (count > 0) {
            LOGGER.warn("该订单已支付完成" + param);
            return;
        }
        String wxtransactionId = (String) param.get("txsn");
        Integer orderId = integralH5Dao.getOrderIdByOrderSn(orderSn);
        if(StringUtils.isEmpty(orderId)){
            throw GlobalException.build("通过orderSn获取orderId失败");
        }
        //获取订单的
        Map orderMap = integralH5Dao.getOrderMapByOrderId(orderId);
        boolean isKnowledge=false;
        if(!StringUtils.isEmpty(orderMap.get("orderGoodsType")) && "2".equals(orderMap.get("orderGoodsType").toString())){
            isKnowledge = true;
        }
        Integer status = 1;
        if(isKnowledge){
            // 更新订单状态
            integralH5Dao.updateOrderInfo(wxtransactionId,1,40,orderSn);
            status = 2;
        }else {
            // 更新订单状态
            integralH5Dao.updateOrderInfo(wxtransactionId,1,20,orderSn);
        }

        // 更新商品订单状态
        integralH5Dao.updateIntegralOrderGoodsInfo(status,orderId);
        //获取订单列表
        String customerId = "";
        String orgId = "";
        if(!StringUtils.isEmpty(orderMap.get("customerId"))){
            customerId = orderMap.get("customerId").toString();
        }
        if(!StringUtils.isEmpty(orderMap.get("orgId"))){
            orgId = orderMap.get("orgId").toString();
        }
        String orderAmount = "0L";
        if(!StringUtils.isEmpty(orderMap.get("orderAmount"))){
            orderAmount = orderMap.get("orderAmount").toString();
        }
        List<Map> maps = integralH5Dao.getGoodsIdsByOrderId(orderId);
        try {
            List<Long> goodsIds = new ArrayList<>();
            for(Map goods : maps){
                Long goodsId = Long.valueOf(goods.get("goodsId").toString());
                Integer goodsNum = Integer.valueOf(goods.get("goodsId").toString());
                if(goodsNum!=null && goodsNum>1){
                    for(int i=0;i<goodsNum;i++){
                        goodsIds.add(goodsId);
                    }
                }else {
                    goodsIds.add(goodsId);
                }
            }
//            scoreActiveCacheService.setCache(orgId,orderSn,orderAmount,goodsIds,customerId);
//            scoreActiveCacheService.cacheOrderNum(orderSn);
        }catch (Exception e){
            LOGGER.info("计算赠送积分和成长值失败");
        }

        //支付完成发送模板消息(调试要注释)
        Map<String, String> orderParam = new HashMap<>();
        orderParam.put("sendType", "payment");
        orderParam.put("orgId", orgId);
        String goodsName = "";
        if(!StringUtils.isEmpty(orderMap.get("goodsName"))){
            goodsName = orderMap.get("goodsName").toString();
        }
        orderParam.put("goodsName", goodsName);
        orderParam.put("orderSn", orderSn);
        orderParam.put("orderAmount", NumberUtils.fenToYuan(Long.valueOf(orderAmount)));
        String orderTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        orderParam.put("orderTime", orderTime);
        String h5url = scrmH5Url + "/userCenter.html?goto=orderlist?activeTab=20";
        String h5urlEncode = null;
        try {
            h5urlEncode = URLEncoder.encode(h5url, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        String url = clientHost + "/personal/login?token=" + purchaseProcessDao.getTokenByOrgId(orgId) + "&m=" + h5urlEncode;
        orderParam.put("url", url);
        orderParam.put("openid", purchaseProcessDao.getOpenIdByCustomerId(customerId));
        //orgId-机构id,goodsName-商品名称,orderSn-订单号,orderAmount-订单金额(非支付金额),orderTime-支付时间,url-订单列表页面,openid-购买人的openid
        this.setTemplateMessageList(orderParam);

        // 冻结时间
        Integer freezeTime = purchaseProcessDao.getFreezeTimeByOrgId(orgId);
        if (freezeTime == null || freezeTime < 0) {
            freezeTime = 30;
        }
        // 正常解冻时间
        String unFreezeTime = df.format(LocalDateTime.now()
                .plusDays(freezeTime));
        // redis取分账信息
        String info = stringRedisTemplate.opsForValue().get(ACS_CREATE_ORDER_INFO + orderSn);
        String goodsInfo = stringRedisTemplate.opsForValue().get(ACS_CREATE_GOODS_INFO + orderSn);
        if (StringUtils.isEmpty(info) || StringUtils.isEmpty(goodsInfo)) {
            LOGGER.warn("订单已过期或无账单信息,orderSn===[{}]", orderSn);
            return;
        }
        Integer payMode = integralH5Dao.getPayModeByOrgId(orgId);
        this.insertGoodsProtectTradeInfo(goodsInfo,orgId,payMode,unFreezeTime,customerId,wxtransactionId);
        List<TradeInfo> tradeInfoList = JSON.parseArray(info, TradeInfo.class);
        for (TradeInfo tradeInfo : tradeInfoList) {
            // 现金
            String to = tradeInfo.getTo();
            Integer receiveRole = tradeInfo.getReceiveRole();
            Integer balance;
            switch (receiveRole) {
                // 根据收款人角色，判断给哪个表加，在哪个表查余额。
                // 先加，再取余额，再记录
                case 0:
                    balance = 0;
                    break;
                case 1:
                    // 大b
                    purchaseProcessDao.updateOrgAccountFreeze(tradeInfo);
                    balance = purchaseProcessDao.getOrgBalanceByOrgId(to);
                    break;
                case 2:
                    // 小b
                    purchaseProcessDao.updateSalesAccountFreeze(tradeInfo);
                    balance = purchaseProcessDao.getSalesBalanceByCustomerId(to);
                    stringRedisTemplate.delete("home:customer_info_" + to);
                    break;
                case 3:
                case 4:
                case 5:
                    // 普通用户
                    purchaseProcessDao.updateCustomerAccountFreeze(tradeInfo);
                    balance = purchaseProcessDao.getUserBalanceByCustomerId(to);
                    stringRedisTemplate.delete("home:customer_info_" + to);
                    break;
                default:
                    balance = 0;
                    break;
            }

            Map<String, Object> map = new HashMap<>();
            map.put("orgId", orgId);
            map.put("payMode", payMode);
            map.put("orderName", tradeInfo.getOrderName());
            map.put("balance", balance);
            map.put("orderSn", tradeInfo.getOrderSn());
            map.put("tradeInfo", tradeInfo);
//            boolean isKnowledge = false;
//            if(tradeInfo!=null && tradeInfo.getIsKnowledge()!=null){
//                isKnowledge =tradeInfo.getIsKnowledge();
//            }
            map.put("unFreezeTime", isKnowledge ? unFreezeTime : null);
            // 生成业务单号
            String busiSn = purchaseProcessNewService.generateBusiSn(tradeInfo.getTradeType(), customerId);
            map.put("busiSn", busiSn);
            map.put("serialNo", wxtransactionId);

            purchaseProcessDao.insertProtectTradeInfo(map);
        }

    }

    public void setTemplateMessageList(Map data) {
    }

    private void insertGoodsProtectTradeInfo(String goodsInfo, String orgId, Integer payMode, String unFreezeTime, String customerId, String wxtransactionId) {
        List<TradeInfo> tradeInfoList = JSON.parseArray(goodsInfo, TradeInfo.class);
        for (TradeInfo tradeInfo : tradeInfoList) {
            // 现金
            String to = tradeInfo.getTo();
            Integer receiveRole = tradeInfo.getReceiveRole();
            Integer balance;
            switch (receiveRole) {
                // 根据收款人角色，判断在哪个表查余额。
                // 取余额，记录
                case -1:
                    balance = 0;
                    break;
                case 0:
                    balance = 0;
                    break;
                case 1:
                    // 大b
                    balance = purchaseProcessDao.getOrgBalanceByOrgId(to);
                    break;
                case 2:
                    // 小b
                    balance = purchaseProcessDao.getSalesBalanceByCustomerId(to);
                    break;
                case 3:
                case 4:
                case 5:
                    // 普通用户
                    balance = purchaseProcessDao.getUserBalanceByCustomerId(to);
                    break;
                default:
                    balance = 0;
                    break;
            }
            Map<String, Object> map = new HashMap<>();
            map.put("orgId", orgId);
            map.put("payMode", payMode);
            map.put("orderName", tradeInfo.getOrderName());
            map.put("balance", balance);
            map.put("orderSn", tradeInfo.getOrderSn());
            Long recId = null;
            if(tradeInfo!=null && tradeInfo.getRecId()!=null){
                recId =tradeInfo.getRecId();
            }
            map.put("recId", recId);
            map.put("tradeInfo", tradeInfo);
            boolean isKnowledge = false;
            if(tradeInfo!=null && tradeInfo.getIsKnowledge()!=null){
                isKnowledge =tradeInfo.getIsKnowledge();
            }
            map.put("unFreezeTime", isKnowledge ? unFreezeTime : null);
            // 生成业务单号
            String busiSn = purchaseProcessNewService.generateBusiSn(tradeInfo.getTradeType(), customerId);
            map.put("busiSn", busiSn);
            map.put("serialNo", wxtransactionId);

            purchaseProcessDao.insertGoodsProtectTradeInfo(map);
        }
    }

    public void cancelShoppingOrder(Long orderId){
        integralH5Dao.closeOrderByOrderId(orderId);
        Map<String,Object> params = new HashMap<>(1);
        params.put("orderId",orderId);
        Map orderInfo = integralH5Dao.getOrderInfoById(Long.valueOf(params.get("orderId").toString()));
        String msg = "取消兑换商品";
        Long score = 0L;
        if(!StringUtils.isEmpty(orderInfo.get("integral"))){
            score = Long.valueOf(orderInfo.get("integral").toString());
        }
        String customerId="";
        if(!StringUtils.isEmpty(orderInfo.get("customerId"))){
            customerId = orderInfo.get("customerId").toString();
        }
        String orgId="";
        if(!StringUtils.isEmpty(orderInfo.get("orgId"))){
            orgId = orderInfo.get("orgId").toString();
        }
        String orderSn="";
        if(!StringUtils.isEmpty(orderInfo.get("orderSn"))){
            orderSn = orderInfo.get("orderSn").toString();
        }
        this.customerIntegralService.addIntegralCustomerLog(customerId,msg, IntegralEnums.customerScore.toString(),score.toString(),IntegralEnums.other.toString(),orgId);
        //增加日志
        Map<String, Object> log = new HashMap<String, Object>();
        log.put("logId", UUID.randomUUID().toString());
        log.put("customerId", customerId);
        log.put("scoreValue",score);
        log.put("scoreType", 6);
        log.put("actionRemark", "取消兑换，订单号"+orderSn+",增加"+score+"积分");
        integralH5Dao.addIntegralLog(log);

        // 订单关闭后恢复库存
        Map<String, Object> order = integralH5Dao.orderByOrderId(orderId);
        Long goodsId = Long.valueOf(order.get("goodsId").toString());
        String skuId = "";
        if (order.get("skuId") != null && !"".equals(order.get("skuId"))) {
            skuId = order.get("skuId").toString();
        }
        Integer goodsNum = 0;
        if (order.get("goodsNum") != null && !"".equals(order.get("goodsNum"))) {
            goodsNum = Integer.valueOf(order.get("goodsNum").toString());
        }        Map<String, Object> mapM = new HashMap<>();
        mapM.put("goodsNum", goodsNum);
        Long goodsIdGoods = goodsId;
        mapM.put("goodsId", goodsIdGoods);
        integralH5Dao.addMallGoodsCount(mapM);
        if (!StringUtils.isEmpty(skuId)) {
            Map<String, Object> map = new HashMap<>();
            map.put("skuId", skuId);
            map.put("goodsNum", goodsNum);
            integralH5Dao.addMallGoodsSkuCount(map);
        }
    }

    public Map<String, Object> checkKnowledgeOrder(Map<String, Object> param) {
        String goodsId = param.get("goodsId").toString();
        return integralH5Dao.getGoodsInfoByGoodsId(goodsId);
    }

}
